package middleware

import (
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"

	"go-pan/internal/metrics"
)

func PrometheusMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		if c.Request.URL.Path == "/metrics" {
			c.Next()
			return
		}

		metrics.HTTPInFlightRequests.Inc()
		start := time.Now()
		reqSize := approximateRequestSize(c.Request)

		c.Next()

		metrics.HTTPInFlightRequests.Dec()

		path := c.FullPath()
		if path == "" {
			path = c.Request.URL.Path
		}

		statusCode := strconv.Itoa(c.Writer.Status())
		method := c.Request.Method
		duration := time.Since(start).Seconds()
		respSize := c.Writer.Size()

		metrics.HTTPRequestsTotal.WithLabelValues(method, path, statusCode).Inc()
		metrics.HTTPRequestDurationSeconds.WithLabelValues(method, path).Observe(duration)

		if reqSize > 0 {
			metrics.HTTPRequestSizeBytes.WithLabelValues(method, path).Observe(reqSize)
		}
		if respSize >= 0 {
			metrics.HTTPResponseSizeBytes.WithLabelValues(method, path, statusCode).Observe(float64(respSize))
		}
	}
}

func approximateRequestSize(r *http.Request) float64 {
	size := 0

	if r.URL != nil {
		size += len(r.URL.Path)
		size += len(r.URL.RawQuery)
	}

	size += len(r.Method)
	size += len(r.Proto)
	size += len(r.Host)

	for name, values := range r.Header {
		size += len(name)
		for _, v := range values {
			size += len(v)
		}
	}

	if r.ContentLength > 0 {
		size += int(r.ContentLength)
	}

	return float64(size)
}
